package com.xhwl.logistics.service.impl.redis;

import com.xhwl.common.exception.BusinessException;
import com.xhwl.logistics.bo.cent.VehicleIntegratedConfigBO;
import com.xhwl.logistics.bo.redis.VehicleTokenBO;
import com.xhwl.logistics.component.LookupVehicleParkingLotHandler;
import com.xhwl.logistics.strategy.IVehicleParkingLotTokenHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.util.Optionals;
import org.springframework.scheduling.annotation.Async;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

//@Service
public class VehicleTokenRedisServiceImpl {

    private final String vehicleTokenPrefix = "cent-logistics:token";

    @Resource(name = "redisTemplateForVehicleToken")
    private ListOperations<String, VehicleTokenBO> listOperationsForVehicleToken;

    @Autowired
    private LookupVehicleParkingLotHandler lookupVehicleParkingLotHandler;

    private List<VehicleTokenBO> getVehicleTokenBOList() {
        return Optional.ofNullable(listOperationsForVehicleToken.range(vehicleTokenPrefix, 0, -1))
                .orElseThrow(() -> new BusinessException("查询redis中的token，redis返回null"));
    }

    public String getTokenByProjectId(Integer projectId) {
        List<VehicleTokenBO> vehicleTokenBOList = getVehicleTokenBOList();
        return vehicleTokenBOList.stream()
                .filter(vehicleTokenBO -> projectId.equals(vehicleTokenBO.getProjectId()))
                .findFirst()
                .orElseThrow(() -> new BusinessException("查询redis中的返回token中，没有该projectId：" + projectId)).getToken();
    }

    @Async("threadPoolTaskExecutorForSchedule")
    public void insertOrUpdateToken(VehicleIntegratedConfigBO vehicleIntegratedConfigBO) {
        Integer projectId = vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProjectId();

        IVehicleParkingLotTokenHandler vehicleParkingLotTokenHandler = lookupVehicleParkingLotHandler.lookupForTokenHandler(vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProductId());
        String token = vehicleParkingLotTokenHandler.getToken(vehicleIntegratedConfigBO);

        /*
        从redis取出list列表，然后在进行新增或者更新操作，这个逻辑步骤本是应该进行同步的（需要上锁），
        不然可能redis会列表会出现相同的VehicleTokenBO，但是因该方法是给xx-job定时调用的，因此就不存在同时间竞争调用了
         */
        VehicleTokenBO tokenBO = new VehicleTokenBO(projectId, token);
        List<VehicleTokenBO> vehicleTokenBOList = getVehicleTokenBOList();

        Optional<VehicleTokenBO> optionalVehicleTokenBO = vehicleTokenBOList.stream()
                .filter(vehicleTokenBO -> projectId.equals(vehicleTokenBO.getProjectId()))
                .findFirst();
        Optionals.ifPresentOrElse(
                optionalVehicleTokenBO,
                vehicleTokenBO -> {
            int index = vehicleTokenBOList.indexOf(vehicleTokenBO);
            listOperationsForVehicleToken.set(vehicleTokenPrefix, index, tokenBO);
                },
                () -> listOperationsForVehicleToken.rightPush(vehicleTokenPrefix, tokenBO));
    }

}
